﻿using System.Collections.Generic;
using System.Linq;

namespace LeRenard.ScriptWars.Model.GridSystem
{
    /// <summary>
    /// Represents a 2d grid
    /// </summary>
    /// <remarks>    
    /// </remarks>
    public class Grid<TValue> : IGrid<TValue>
        where TValue : class
    {
        #region Properties
        /// <summary>
        /// Gets the grid's size.
        /// </summary>
        public GridSize Size { get { return _size; } }
        private readonly GridSize _size;

        /// <summary>
        /// Gets all cells on the grid.
        /// </summary>
        public IEnumerable<IGridCell<TValue>> Cells 
        {
            get {
                for (int y = 0; y < Size.Height; y++) {
                    for (int x = 0; x < Size.Width; x++) {
                        yield return _layout[y, x];
                    }
                }
            }
        }

        /// <summary>
        /// Gets the amount of cells.
        /// </summary>
        public int CellCount
        {
            get {
                if(_cellCount == -1)
                    _cellCount = Cells.Count();

                return _cellCount;
            }
        }
        private int _cellCount = -1;

        /// <summary>
        /// Gets the grid's layout.
        /// The first dimension is Y/rows/height,
        /// The second dimension is X/columns/width.
        /// </summary>
        public IGridCell<TValue>[,] Layout { get { return _layout; /*return _layout.Clone() as IGridCell<TValue>[,];*/ } }
        private readonly IGridCell<TValue>[,] _layout;
        #endregion

        #region Construction
        /// <summary>
        /// Creates a new <see cref="Grid"/> based on a given size.
        /// </summary>
        /// <param name="size">The grid's size.</param>
        public Grid(GridSize size, IGridInitializer<TValue> initializer = null)
        {
            ThrowIf.Null(() => size);

            if (initializer == null)
                initializer = new DefaultGridInitializer<TValue>();

            _size = size;            
            _layout = initializer.Initialize(this);
        }
        #endregion

        #region Methods
        /// <summary>
        /// Gets the position for a <see cref="GridCell"/> with a specific value.
        /// </summary>
        public GridPosition GetPositionFor<TValue>(TValue value)
        {
            for (int y = 0; y < Size.Height; y++) {
                for (int x = 0; x < Size.Width; x++) {
                    var cell = _layout[y, x];
                    if (ReferenceEquals(cell.Value, value)) {
                        return new GridPosition(x, y);
                    }                    
                }
            }

            return null;
        }
        #endregion
    }
}
